package sisop;

import java.util.LinkedList;
import java.util.Map;
import java.io.*;

/**
 * Implementacion de un planificador Multilevel Feedback Queue. 
 * Esta clase esta vacia.
 */ 
class MFQ extends Scheduler {

	static private int quanta[] = {5,15,45};

	static private int none		= -1;
	static private int high		= 0;
	static private int middle	= 1;
	static private int low		= 2;

	private int finished_tasks;
	private int current_time;
	private Task current_task;
	private int current_priority;
	private int round_time;
	private int switch_time;

	private LinkedList<LinkedList<Task>> queues;
	
	public MFQ() {
		super("MFQ");
	}

	protected void scheduler_init() {
	
		queues = new LinkedList<LinkedList<Task>>();
		queues.add(0,new LinkedList<Task>());
		queues.add(1,new LinkedList<Task>());
		queues.add(2,new LinkedList<Task>());

		finished_tasks=0;
		current_time=-1;
		current_task=null;
		round_time=0;
		switch_time=2;
	}


	public String scheduler_next() {
		current_time++;

		SelectReadyTasks();

		if (switch_time<2)
		{
			switch_time++;
			return IDLE_TASK;
		}
		else
		{
			if (current_task!=null && (current_task.ttime>=current_task.ptime || round_time>=quanta[current_priority]))
			{
				queues.get(current_priority).remove();
				current_task.ftime=current_time;

				if (current_task.ttime<current_task.ptime)
				{
					if (current_priority<low)
						queues.get(current_priority+1).addLast(current_task);
					else
						queues.get(current_priority).addLast(current_task);
				}
				else
				{
					finished_tasks++;
					
					if (task_set.size()==finished_tasks)
						return null;
				}

				switch_time=1;
				current_priority=none;
				current_task=null;
				return IDLE_TASK;
			}
			else
			{
				if (current_task==null)
				{
					for (int i=0;i<low+1;i++)
					{
						if (queues.get(i).size()>0)
						{
							current_priority = i;
							current_task = queues.get(i).getFirst();
							current_task.wtime += (current_task.ftime<0 ? current_time-current_task.rtime :current_time-current_task.ftime);
							round_time=0;
							break;
						}
					}
					
					if (current_task==null)
						return IDLE_TASK;
				}
				current_task.ttime++;
				round_time++;
			}
		}

		return current_task.name;
	}

	private void SelectReadyTasks() {
		for (Task task: this.task_set)
			if (task.rtime==current_time)
				queues.get(high).add(task);
	}

}
